#ifndef _P2PSOCKET_H_
#define _P2PSOCKET_H_

#include <winsock2.h>
#include <netlib/net/UDPSocket.h>
#include <utillib/io/log.h>

#define			P2P_ID_LENGTH		32
namespace netlib
{
	namespace net
	{
		class P2PSocket : public netlib::net::UDPSocket
		{
		public:
			P2PSocket( SocketManager *socketManager );
			virtual ~P2PSocket();
		public:
			UDPSocket::ConnectInfo *p2pConnect( const char *serverIP, WORD managerPort, const char *loginID, const char *peerConnectID );
			UDPSocket::ConnectInfo *p2pConnect( DWORD serverIP, WORD managerPort, const char *loginID, const char *peerConnectID );

			DWORD getP2PError(){ return ( m_p2pError ); 	};
			virtual netlib::packet::Packet *putReceiveMessage(unsigned char *receive , unsigned short int size , ConnectInfo *info );
		private:
			UDPSocket::ConnectInfo *p2pServerConnect( const char *serverIP, WORD serverPort );
			UDPSocket::ConnectInfo *p2pServerConnect( DWORD serverIP, WORD serverPort );

			void sendUDPInformationReq();
			void sendLocalPeerInfo( DWORD myIP = 0, WORD port = 0 );
			void sendServerInfoReq();

			bool sendUDPConditionReq( DWORD serverIP, WORD port );

			bool connectManagerServer( DWORD serverIP, WORD port );
			
			UDPSocket::ConnectInfo *checkP2PConnect();
			DWORD m_p2pError;

			UDPSocket::ConnectInfo *m_managerServerInfo;
	
			bool onReceiveInternalProcess( netlib::packet::Packet *packet );

			bool checkNATConditionAck( netlib::packet::Packet *packet );
			bool serverInfoAck( netlib::packet::Packet *packet );
			bool UDPInformationAck( netlib::packet::Packet *packet );

			DWORD m_peerPublicIP;
			DWORD m_peerInternalIP;
			WORD m_firstPort;
			WORD m_secondPort;
			char m_userID[ P2P_ID_LENGTH + 1 ];
			char m_peerConnectID[ P2P_ID_LENGTH + 1 ];
			
		public:
			enum
			{
				P2P_NO_ERROR		= 1,
				P2P_NO_EXIST_USER,
				P2P_FAIL_MANAGER_SERVER_CONNECT,
				P2P_TIMEOUT_GET_SERVER_INFO,
				P2P_TIMEOUT_GET_PEER_INFO,
				P2P_ENABLE_NAT,
				P2P_DIABLE_NAT,
				P2P_INTERNAL_NAT_EACH_HOST,
				P2P_TIMEOUT_GET_CHECK_UDP_CONDTION,
				P2P_FAIL_CHECK_UDP_CONDITION_SERVER_CONNECT,
			};
			void setLog( utillib::io::Log *log ){ m_log = log;};
		private:
			utillib::io::Log *m_log;
			utillib::util::Event m_connectEvent;

			bool m_checkNATCondition;
			bool m_checkSymAttack;
		};
	};
};

#endif